package org.dandsoft.blackbox.laboratory.tests.replace;

import org.dandsoft.blackbox.laboratory.tools.generator.Function;
import org.dandsoft.blackbox.laboratory.tools.generator.SignalsGenerator;
import org.dandsoft.blackbox.SignalId;
import org.dandsoft.blackbox.Time;
import org.dandsoft.blackbox.counter.RelationshipCounter;

import java.util.*;


/**
 * @author Vilyuzhanin Denis (Fin)
 */
public class FunctionFinder {

    private final static int STEPS_COUNT = 100;

    public static void main(String[] args) {
        find("4", Function.generateRandom(0, 4, 0.2), 4);
    }

    private static void run(Function function, SignalsGenerator generator, List<Layer> layers) {
        List<Map<SignalId, RelationshipCounter>> counters = new ArrayList<Map<SignalId, RelationshipCounter>>(layers.size());
        for (int i = 0; i < layers.size(); i++) {
            counters.add(new Hashtable<SignalId, RelationshipCounter>());
        }

        for (int time = 0; time < STEPS_COUNT; time++) {
            Time timeObj = new Time(time);
            Map<SignalId, Integer> values = generator.generate();
            Integer result = function.getValue(values);
            if (result == null) {
                result = 0;
            }
            System.out.println(result + " - " + values.toString());

            Set<SignalId> image = new HashSet<SignalId>();
            for (Map.Entry<SignalId, Integer> entry : values.entrySet()) {
                if (entry.getValue() > 0) {
                    image.add(entry.getKey());
                }
            }

            System.out.println("------Replacing-------");
            for (int i = 0; i < layers.size(); i++) {
                print(i, image);

                count(counters.get(i), image, result);

                Layer layer = layers.get(i);
                layer.input(image);
                layer.handle(timeObj);
                image = layer.output();
            }
            System.out.println("------------------------");
            System.out.println();
        }

        for (int i = 0; i < counters.size(); i++) {
            System.out.println("[ LEVEL " + i + " ]");
            Map<SignalId, RelationshipCounter> levels = counters.get(i);
            System.out.println("SignalsCount: " + levels.size());
            for (Map.Entry<SignalId, RelationshipCounter> counterEntry : levels.entrySet()) {
                System.out.println(" + " + counterEntry.getKey().toString() +
                        "[" + (counterEntry.getValue().getNormalActive() + counterEntry.getValue().getNormalPassive()) + "-" +
                        (counterEntry.getValue().getInversionActive() + counterEntry.getValue().getNormalPassive()) + "] " +
                        counterEntry.getValue().toString());

            }
        }

        printLevels(layers);
    }

    private static void count(Map<SignalId, RelationshipCounter> levelCounters, Set<SignalId> image, int result) {
        for (SignalId signalId : image) {
            if (!levelCounters.containsKey(signalId)) {
                levelCounters.put(signalId, new RelationshipCounter());
            }
        }

        for (Map.Entry<SignalId, RelationshipCounter> counterEntry : levelCounters.entrySet()) {
            if (image.contains(counterEntry.getKey())) {
                //сигнал есть
                if (result == 0) {
                    //сигнал есть, а функция пассивна
                    counterEntry.getValue().incrementInversionPassive();
                } else {
                    //сигнал есть, и функция активна
                    counterEntry.getValue().incrementNormalActive();
                }
            } else {
                //сигнала нет
                if (result == 0) {
                    //сигнал нет, а функция активна
                    counterEntry.getValue().incrementInversionActive();
                } else {
                    //сигнал нет и функция пассивна
                    counterEntry.getValue().incrementNormalPassive();
                }
            }
        }
    }

    private static void print(int level, Set<SignalId> image) {
        System.out.println(level + " [ ");
        for (SignalId signalId : image) {
            System.out.print(" " + signalId + " ");
        }
        System.out.println(" ]");
    }

    private static void printLevels(List<Layer> levels) {
        for (Layer layer : levels) {
            System.out.println("+++++++LAYER " + layer.getLevel() + "++++++");
            layer.print();
        }
    }

    public static void find(String name, Function function, int layersCount) {
        System.out.println("========START " + name.toUpperCase() + "========");
        List<Layer> layers = new LinkedList<Layer>();
        for (int i = 0; i < layersCount; i++) {
            Layer layer = new Layer();
            layer.setLevel(i);
            layer.getReplacer().setSequence((int) Math.pow(10, i + 1));
            layer.getReplacer().setMaxTriggersCount(4);
            layer.getReplacer().setImageLength(2);
            layers.add(layer);
        }
        function.printFunction();
        SignalsGenerator generator = new SignalsGenerator(function.getArguments());
        run(function, generator, layers);
        System.out.println("========FINISH " + name.toUpperCase() + "========");
    }
}